package com.joker.demo.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.joker.demo.admin.domain.dto.JobLogQueryDTO;
import com.joker.demo.admin.domain.dto.JobDailyExecutionQueryDTO;
import com.joker.demo.admin.domain.po.JobInfoPO;
import com.joker.demo.admin.domain.po.JobLogPO;
import com.joker.demo.admin.domain.po.JobRegistryPO;
import com.joker.demo.admin.domain.vo.JobLogVO;
import com.joker.demo.admin.domain.vo.JobDailyExecutionVO;
import com.joker.demo.admin.domain.vo.JobExecutionDetailVO;
import com.joker.demo.admin.domain.vo.JobExecutorStatisticsVO;
import com.joker.demo.admin.domain.vo.ExecutorRegistryVO;
import com.joker.demo.admin.domain.vo.JobHourlyStatisticsVO;
import com.joker.demo.admin.domain.vo.PageResult;
import com.joker.demo.admin.mapper.JobInfoMapper;
import com.joker.demo.admin.mapper.JobLogMapper;
import com.joker.demo.admin.mapper.JobRegistryMapper;
import com.joker.demo.admin.service.JobLogService;
import com.joker.demo.core.domain.enums.JobRunStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 任务日志服务实现类
 *
 * @author : feixiang.li
 * @since : 2025-07-26 19:38
 */
@Service
@Slf4j
public class JobLogServiceImpl implements JobLogService {

    @Resource
    private JobLogMapper jobLogMapper;

    @Resource
    private JobInfoMapper jobInfoMapper;

    @Resource
    private JobRegistryMapper jobRegistryMapper;

    @Override
    public PageResult<JobLogVO> queryJobLogPage(JobLogQueryDTO jobLogQueryDTO) {
        if (Objects.isNull(jobLogQueryDTO)) {
            return PageResult.of(Collections.emptyList(), 0L, 1L, 10L);
        }

        // 构建查询条件
        LambdaQueryWrapper<JobLogPO> queryWrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(jobLogQueryDTO.getJobId())) {
            queryWrapper.eq(JobLogPO::getJobId, jobLogQueryDTO.getJobId());
        }
        if (Objects.nonNull(jobLogQueryDTO.getTriggerCode())) {
            queryWrapper.eq(JobLogPO::getTriggerCode, jobLogQueryDTO.getTriggerCode());
        }
        if (Objects.nonNull(jobLogQueryDTO.getStartTime())) {
            queryWrapper.ge(JobLogPO::getTriggerTime, jobLogQueryDTO.getStartTime());
        }
        if (Objects.nonNull(jobLogQueryDTO.getEndTime())) {
            queryWrapper.le(JobLogPO::getTriggerTime, jobLogQueryDTO.getEndTime());
        }
        if (Objects.nonNull(jobLogQueryDTO.getExecutorAddress()) && !jobLogQueryDTO.getExecutorAddress().trim().isEmpty()) {
            queryWrapper.like(JobLogPO::getExecutorAddress, jobLogQueryDTO.getExecutorAddress());
        }

        // 设置分页参数
        long current = jobLogQueryDTO.getPageNum() != null ? jobLogQueryDTO.getPageNum() : 1L;
        long size = jobLogQueryDTO.getPageSize() != null ? jobLogQueryDTO.getPageSize() : 10L;
        Page<JobLogPO> page = new Page<>(current, size);

        // 按触发时间降序排序
        queryWrapper.orderByDesc(JobLogPO::getTriggerTime);

        // 执行分页查询
        IPage<JobLogPO> pageResult = jobLogMapper.selectPage(page, queryWrapper);

        // 获取任务信息用于填充任务名称和应用名称
        List<Long> jobIds = pageResult.getRecords().stream()
                .map(jobLog -> Long.valueOf(jobLog.getJobId()))
                .distinct()
                .collect(Collectors.toList());

        Map<Long, JobInfoPO> jobInfoMap = Collections.emptyMap();
        if (!jobIds.isEmpty()) {
            LambdaQueryWrapper<JobInfoPO> jobInfoWrapper = new LambdaQueryWrapper<>();
            jobInfoWrapper.in(JobInfoPO::getId, jobIds);
            List<JobInfoPO> jobInfoList = jobInfoMapper.selectList(jobInfoWrapper);
            jobInfoMap = jobInfoList.stream()
                    .collect(Collectors.toMap(JobInfoPO::getId, jobInfo -> jobInfo, (existing, replacement) -> existing));
        }

        // 转换为VO
        final Map<Long, JobInfoPO> finalJobInfoMap = jobInfoMap;
        List<JobLogVO> jobLogVOList = pageResult.getRecords().stream()
                .map(jobLog -> convertToVO(jobLog, finalJobInfoMap.get(Long.valueOf(jobLog.getJobId()))))
                .collect(Collectors.toList());

        return PageResult.of(jobLogVOList, pageResult.getTotal(), current, size);
    }

    @Override
    public JobLogVO getJobLogDetail(Integer jobId) {
        if (Objects.isNull(jobId)) {
            return null;
        }

        // 查询最新的任务日志
        LambdaQueryWrapper<JobLogPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JobLogPO::getJobId, jobId);
        queryWrapper.orderByDesc(JobLogPO::getTriggerTime);
        queryWrapper.last("limit 1");

        JobLogPO jobLogPO = jobLogMapper.selectOne(queryWrapper);
        if (jobLogPO == null) {
            return null;
        }

        // 查询任务信息
        JobInfoPO jobInfoPO = jobInfoMapper.selectById(jobId);

        return convertToVO(jobLogPO, jobInfoPO);
    }

    @Override
    public boolean stopJob(Integer jobId) {
        if (Objects.isNull(jobId)) {
            return false;
        }

        try {
            // TODO: 实现手动终止任务的逻辑
            // 这里需要调用调度器来终止正在运行的任务
            log.info("手动终止任务，jobId: {}", jobId);
            return true;
        } catch (Exception e) {
            log.error("手动终止任务失败，jobId: {}", jobId, e);
            return false;
        }
    }

    /**
     * 将PO转换为VO
     */
    private JobLogVO convertToVO(JobLogPO jobLogPO, JobInfoPO jobInfoPO) {
        JobLogVO jobLogVO = BeanUtil.copyProperties(jobLogPO, JobLogVO.class);

        // 设置任务信息
        if (jobInfoPO != null) {
            jobLogVO.setJobName(jobInfoPO.getJobName());
            jobLogVO.setGroupName(jobInfoPO.getGroupName());
        }

        // 设置执行状态描述
        if (jobLogPO.getTriggerCode() != null) {
            JobRunStatusEnum statusEnum = JobRunStatusEnum.getByCode(jobLogPO.getTriggerCode());
            if (statusEnum != null) {
                jobLogVO.setTriggerCodeDesc(statusEnum.getDesc());
            }
        }
        return jobLogVO;
    }

    @Override
    public JobDailyExecutionVO queryJobDailyExecution(JobDailyExecutionQueryDTO queryDTO) {
        if (Objects.isNull(queryDTO) || Objects.isNull(queryDTO.getJobId()) || Objects.isNull(queryDTO.getQueryDate())) {
            return null;
        }

        try {
            // 解析查询日期
            Date queryDate = DateUtil.parseDate(queryDTO.getQueryDate());
            Date startTime = DateUtil.beginOfDay(queryDate);
            Date endTime = DateUtil.endOfDay(queryDate);

            // 构建查询条件
            LambdaQueryWrapper<JobLogPO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(JobLogPO::getJobId, queryDTO.getJobId());
            queryWrapper.ge(JobLogPO::getTriggerTime, startTime);
            queryWrapper.le(JobLogPO::getTriggerTime, endTime);

            // 添加可选查询条件
            if (Objects.nonNull(queryDTO.getTriggerCode())) {
                queryWrapper.eq(JobLogPO::getTriggerCode, queryDTO.getTriggerCode());
            }
            if (Objects.nonNull(queryDTO.getExecutorAddress()) && !queryDTO.getExecutorAddress().trim().isEmpty()) {
                queryWrapper.like(JobLogPO::getExecutorAddress, queryDTO.getExecutorAddress());
            }

            // 按触发时间升序排序
            queryWrapper.orderByAsc(JobLogPO::getTriggerTime);

            // 查询所有符合条件的日志
            List<JobLogPO> jobLogList = jobLogMapper.selectList(queryWrapper);

            // 查询任务信息
            JobInfoPO jobInfo = jobInfoMapper.selectById(queryDTO.getJobId());

            // 构建返回结果
            JobDailyExecutionVO result = new JobDailyExecutionVO();
            result.setJobId(queryDTO.getJobId());
            result.setQueryDate(queryDTO.getQueryDate());

            if (jobInfo != null) {
                result.setJobName(jobInfo.getJobName());
                result.setGroupName(jobInfo.getGroupName());
            }

            // 统计执行情况
            int totalExecutions = jobLogList.size();
            int successCount = 0;
            int failureCount = 0;
            int runningCount = 0;
            long totalTimeCost = 0;
            long maxTimeCost = 0;
            long minTimeCost = Long.MAX_VALUE;

            List<JobExecutionDetailVO> executionDetails = new ArrayList<>();
            Map<String, JobExecutorStatisticsVO> executorStatsMap = new HashMap<>();
            Map<Integer, JobHourlyStatisticsVO> hourlyStatsMap = new HashMap<>();

            for (JobLogPO jobLog : jobLogList) {
                // 统计执行状态
                if (jobLog.getTriggerCode() != null) {
                    if (jobLog.getTriggerCode() == JobRunStatusEnum.COMPLETED.getCode()) {
                        successCount++;
                    } else if (jobLog.getTriggerCode() == JobRunStatusEnum.FAILED.getCode()) {
                        failureCount++;
                    } else if (jobLog.getTriggerCode() == JobRunStatusEnum.RUNNING.getCode()) {
                        runningCount++;
                    }
                }

                // 统计执行时间
                if (jobLog.getTimeCost() != null) {
                    totalTimeCost += jobLog.getTimeCost();
                    maxTimeCost = Math.max(maxTimeCost, jobLog.getTimeCost());
                    minTimeCost = Math.min(minTimeCost, jobLog.getTimeCost());
                }

                // 构建执行详情
                JobExecutionDetailVO detail = convertToExecutionDetail(jobLog, jobInfo);
                executionDetails.add(detail);

                // 统计执行器信息
                if (jobLog.getExecutorAddress() != null) {
                    executorStatsMap.computeIfAbsent(jobLog.getExecutorAddress(), k -> {
                        JobExecutorStatisticsVO stats = new JobExecutorStatisticsVO();
                        stats.setExecutorAddress(k);
                        stats.setExecutionCount(0);
                        stats.setSuccessCount(0);
                        stats.setFailureCount(0);
                        stats.setAverageExecutionTime(0L);
                        return stats;
                    });

                    JobExecutorStatisticsVO stats = executorStatsMap.get(jobLog.getExecutorAddress());
                    stats.setExecutionCount(stats.getExecutionCount() + 1);
                    if (jobLog.getTriggerCode() != null) {
                        if (jobLog.getTriggerCode() == JobRunStatusEnum.COMPLETED.getCode()) {
                            stats.setSuccessCount(stats.getSuccessCount() + 1);
                        } else if (jobLog.getTriggerCode() == JobRunStatusEnum.FAILED.getCode()) {
                            stats.setFailureCount(stats.getFailureCount() + 1);
                        }
                    }
                }

                // 统计小时分布
                if (jobLog.getTriggerTime() != null) {
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(jobLog.getTriggerTime());
                    final int hour = cal.get(Calendar.HOUR_OF_DAY);

                    hourlyStatsMap.computeIfAbsent(hour, k -> {
                        JobHourlyStatisticsVO stats = new JobHourlyStatisticsVO();
                        stats.setHour(k);
                        stats.setExecutionCount(0);
                        stats.setSuccessCount(0);
                        stats.setFailureCount(0);
                        stats.setAverageExecutionTime(0L);
                        return stats;
                    });

                    JobHourlyStatisticsVO stats = hourlyStatsMap.get(hour);
                    stats.setExecutionCount(stats.getExecutionCount() + 1);
                    if (jobLog.getTriggerCode() != null) {
                        if (jobLog.getTriggerCode() == JobRunStatusEnum.COMPLETED.getCode()) {
                            stats.setSuccessCount(stats.getSuccessCount() + 1);
                        } else if (jobLog.getTriggerCode() == JobRunStatusEnum.FAILED.getCode()) {
                            stats.setFailureCount(stats.getFailureCount() + 1);
                        }
                    }
                }
            }

            // 设置统计结果
            result.setTotalExecutions(totalExecutions);
            result.setSuccessCount(successCount);
            result.setFailureCount(failureCount);
            result.setRunningCount(runningCount);
            result.setAverageExecutionTime(totalExecutions > 0 ? totalTimeCost / totalExecutions : 0L);
            result.setMaxExecutionTime(maxTimeCost);
            result.setMinExecutionTime(minTimeCost == Long.MAX_VALUE ? 0L : minTimeCost);
            result.setExecutionDetails(executionDetails);

            // 处理执行器统计信息
            List<JobExecutorStatisticsVO> executorStatistics = new ArrayList<>();
            for (JobExecutorStatisticsVO stats : executorStatsMap.values()) {
                // 计算平均执行时间
                if (stats.getExecutionCount() > 0) {
                    long totalTime = jobLogList.stream()
                            .filter(log -> log.getExecutorAddress() != null && log.getExecutorAddress().equals(stats.getExecutorAddress()))
                            .mapToLong(log -> log.getTimeCost() != null ? log.getTimeCost() : 0)
                            .sum();
                    stats.setAverageExecutionTime(totalTime / stats.getExecutionCount());
                }

                // 如果需要包含注册信息
                if (Boolean.TRUE.equals(queryDTO.getIncludeRegistryInfo())) {
                    ExecutorRegistryVO registryInfo = getExecutorRegistryInfo(stats.getExecutorAddress());
                    stats.setRegistryInfo(registryInfo);
                }

                executorStatistics.add(stats);
            }
            result.setExecutorStatistics(executorStatistics);

            // 处理小时统计信息
            List<JobHourlyStatisticsVO> hourlyStatistics = new ArrayList<>();
            for (int hour = 0; hour < 24; hour++) {
                JobHourlyStatisticsVO stats = hourlyStatsMap.get(hour);
                if (stats == null) {
                    stats = new JobHourlyStatisticsVO();
                    stats.setHour(hour);
                    stats.setExecutionCount(0);
                    stats.setSuccessCount(0);
                    stats.setFailureCount(0);
                    stats.setAverageExecutionTime(0L);
                } else {
                    // 计算平均执行时间
                    if (stats.getExecutionCount() > 0) {
                        final int finalHour = hour;
                        long totalTime = jobLogList.stream()
                                .filter(log -> {
                                    if (log.getTriggerTime() == null) return false;
                                    Calendar cal = Calendar.getInstance();
                                    cal.setTime(log.getTriggerTime());
                                    return cal.get(Calendar.HOUR_OF_DAY) == finalHour;
                                })
                                .mapToLong(log -> log.getTimeCost() != null ? log.getTimeCost() : 0)
                                .sum();
                        stats.setAverageExecutionTime(totalTime / stats.getExecutionCount());
                    }
                }
                hourlyStatistics.add(stats);
            }
            result.setHourlyStatistics(hourlyStatistics);

            return result;

        } catch (Exception e) {
            log.error("查询任务一天内执行情况失败，jobId: {}, queryDate: {}", queryDTO.getJobId(), queryDTO.getQueryDate(), e);
            return null;
        }
    }

    /**
     * 转换为执行详情VO
     */
    private JobExecutionDetailVO convertToExecutionDetail(JobLogPO jobLog, JobInfoPO jobInfo) {
        JobExecutionDetailVO detail = new JobExecutionDetailVO();
        detail.setId(jobLog.getId().intValue());
        detail.setTriggerTime(jobLog.getTriggerTime());
        detail.setStartTime(jobLog.getStartTime());
        detail.setEndTime(jobLog.getEndTime());
        detail.setTriggerCode(jobLog.getTriggerCode());
        detail.setExecutorAddress(jobLog.getExecutorAddress());
        detail.setExecutorHandler(jobLog.getExecutorHandler());
        detail.setTimeCost(jobLog.getTimeCost());
        detail.setTriggerMsg(jobLog.getTriggerMsg());

        // 设置状态描述
        if (jobLog.getTriggerCode() != null) {
            JobRunStatusEnum statusEnum = JobRunStatusEnum.getByCode(jobLog.getTriggerCode());
            if (statusEnum != null) {
                detail.setTriggerCodeDesc(statusEnum.getDesc());
            }
        }

        return detail;
    }

    /**
     * 获取执行器注册信息
     */
    private ExecutorRegistryVO getExecutorRegistryInfo(String executorAddress) {
        if (executorAddress == null || executorAddress.trim().isEmpty()) {
            return null;
        }

        try {
            LambdaQueryWrapper<JobRegistryPO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(JobRegistryPO::getRegistryKey, executorAddress);
            queryWrapper.orderByDesc(JobRegistryPO::getCreateTime);
            queryWrapper.last("limit 1");

            JobRegistryPO registry = jobRegistryMapper.selectOne(queryWrapper);
            if (registry != null) {
                ExecutorRegistryVO registryVO = new ExecutorRegistryVO();
                registryVO.setExecutorAddress(registry.getRegistryKey());
                // 将 LocalDateTime 转换为 Date
                if (registry.getCreateTime() != null) {
                    registryVO.setRegistryTime(Date.from(registry.getCreateTime().atZone(java.time.ZoneId.systemDefault()).toInstant()));
                }
                if (registry.getUpdateTime() != null) {
                    registryVO.setLastHeartbeatTime(Date.from(registry.getUpdateTime().atZone(java.time.ZoneId.systemDefault()).toInstant()));
                }
                // 这里可以根据实际业务逻辑设置注册状态
                registryVO.setRegistryStatus(1); // 假设1表示正常
                registryVO.setRegistryStatusDesc("正常");
                return registryVO;
            }
        } catch (Exception e) {
            log.error("获取执行器注册信息失败，executorAddress: {}", executorAddress, e);
        }

        return null;
    }
} 